#include "PaintedButton.h"

///Copyright (c) 2009-2010 T. Klepzig 

PaintedButton::PaintedButton(HWND parentWindow)
{
	this->parentHWnd = parentWindow;
	visible = false;
	checkable = false;
	buttonHover = false;
	buttonChecked = false;
	onClickPtr = 0;
	onMouseEnterPtr = 0;
	onMouseLeavePtr = 0;
	onRightMouseButtonUpPtr = 0;
	gradientMode = GradientMode::Vertical;
	textColor = RGB(255, 255, 255);
	textFormat = DT_LEFT | DT_END_ELLIPSIS | DT_VCENTER | DT_SINGLELINE;
	fontSize = 12;
	fontWeight = FW_NORMAL;
}

PaintedButton::~PaintedButton()
{
}


bool PaintedButton::HandleWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	bool handled = false;	

	if (uMsg == WM_ACTIVATE && wParam == WA_INACTIVE && visible)
	{
		buttonHover = false;
		InvalidateRect(hWnd, &bounds, TRUE); 
	}
	else if (uMsg == WM_RBUTTONUP && visible)
	{
		POINT pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

		if (Utilities::RectContainsPoint(bounds, pos))
		{
			CallPBEvent(onRightMouseButtonUpPtr);
			handled = true;
		}
	}
	else if (uMsg == WM_LBUTTONDOWN && visible)
	{
		POINT pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
		
		if (Utilities::RectContainsPoint(bounds, pos))
			handled = true;
	}
	else if (uMsg == WM_LBUTTONUP && visible)
	{
		POINT pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

		if (Utilities::RectContainsPoint(bounds, pos))
		{
			if (checkable)	
				buttonChecked = !buttonChecked;

			CallPBEvent(onClickPtr);

			handled = true;
			InvalidateRect(hWnd, &bounds, TRUE); 
		}
	}
	else if (uMsg == WM_MOUSELEAVE && visible)
	{
		if (buttonHover)
		{
			CallPBEvent(onMouseLeavePtr);
			buttonHover = false;
			InvalidateRect(hWnd, &bounds, TRUE); 
		}
	}
	else if (uMsg == WM_MOUSEMOVE && visible)
	{		
		TRACKMOUSEEVENT tme={0};
		tme.cbSize = sizeof(TRACKMOUSEEVENT);
		tme.hwndTrack = hWnd;
		tme.dwFlags = TME_LEAVE;
		TrackMouseEvent(&tme);

		POINT pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

		if (!buttonHover && Utilities::RectContainsPoint(bounds, pos))
		{
			CallPBEvent(onMouseEnterPtr);
			buttonHover = true;
			handled = true;
			InvalidateRect(hWnd, &bounds, TRUE); 
		}
		else if (buttonHover && !Utilities::RectContainsPoint(bounds, pos))
		{
			CallPBEvent(onMouseLeavePtr);
			buttonHover = false;
			handled = true;
			InvalidateRect(hWnd, &bounds, TRUE); 
		}
	}

	return handled;
}

void PaintedButton::HandlePainting(HDC hdc)
{
	if (visible)
	{
		RECT textRect = {bounds.left + 5 + textPadding.left, bounds.top + textPadding.top, bounds.right - 5 - textPadding.right, bounds.bottom - textPadding.bottom};
		Utilities::DrawDefaultText(textRect, hdc, text.c_str(), fontSize, textColor, textFormat, fontWeight);


		Graphics graphics(hdc);
		graphics.SetSmoothingMode(SmoothingModeHighQuality);

		if (buttonHover || buttonChecked)
		{
			GraphicsPath fillPath1;
			GraphicsPath fillPath2;
			GraphicsPath borderPath;
			GraphicsPath secondaryBorderPath;
			GraphicsPath tertiaryBorderPath;

			Pen	borderPen(Color(160, 190, 190, 190));
			Pen	secondaryBorderPen(Color(140, 20, 20, 20));
			Pen	tertiaryBorderPen(Color(120, 190, 190, 190));

			Rect gradientRect1;
			Rect gradientRect2;		
			LinearGradientMode linearGradientMode;

			if (gradientMode == GradientMode::Vertical)
			{
				gradientRect1.X = bounds.left;
				gradientRect1.Y = bounds.top;
				gradientRect1.Width = RECTWIDTH(bounds);
				gradientRect1.Height = RECTHEIGHT(bounds) / 2 + 1;

				gradientRect2.X = bounds.left;
				gradientRect2.Y = bounds.top + RECTHEIGHT(bounds) / 2 - 1;
				gradientRect2.Width = RECTWIDTH(bounds);
				gradientRect2.Height = RECTHEIGHT(bounds) / 2 + 1;

				RECT rect1 = {gradientRect1.GetLeft(), gradientRect1.GetTop(), gradientRect1.GetRight(), gradientRect1.GetBottom()};
				RECT rect2 = {gradientRect2.GetLeft(), gradientRect2.GetTop(), gradientRect2.GetRight(), gradientRect2.GetBottom()};

				Utilities::CreateRoundRectPath(&fillPath1, rect1, 4, 4, 0, 0, -2, -2, -2, 0);
				Utilities::CreateRoundRectPath(&fillPath2, rect2, 0, 0, 4, 4, -2, 0, -2, -2);

				linearGradientMode = LinearGradientMode::LinearGradientModeVertical;
			}
			else if (gradientMode == GradientMode::Horizontal)
			{
				gradientRect1.X = bounds.left;
				gradientRect1.Y = bounds.top;
				gradientRect1.Width = RECTWIDTH(bounds) / 2 + 1;
				gradientRect1.Height = RECTHEIGHT(bounds);

				gradientRect2.X = bounds.left + RECTWIDTH(bounds) / 2 - 1;
				gradientRect2.Y = bounds.top;
				gradientRect2.Width = RECTWIDTH(bounds) / 2 + 1;
				gradientRect2.Height = RECTHEIGHT(bounds);

				RECT rect1 = {gradientRect1.GetLeft(), gradientRect1.GetTop(), gradientRect1.GetRight(), gradientRect1.GetBottom()};
				RECT rect2 = {gradientRect2.GetLeft(), gradientRect2.GetTop(), gradientRect2.GetRight(), gradientRect2.GetBottom()};


				Utilities::CreateRoundRectPath(&fillPath1, rect1, 4, 0, 0, 4, -2, -2, 0, -2);
				Utilities::CreateRoundRectPath(&fillPath2, rect2, 0, 4, 4, 0, 0, -2, -2, -2);

				linearGradientMode = LinearGradientMode::LinearGradientModeHorizontal;
			}
			BYTE alpha = 60;
			LinearGradientBrush linearGradientBrush1(gradientRect1, Color(alpha, 180, 180, 180), Color(alpha, 120, 120, 120), linearGradientMode);
			LinearGradientBrush linearGradientBrush2(gradientRect2, Color(alpha, 70, 70, 70), Color(alpha, 180, 180, 180), linearGradientMode);

			
			Utilities::CreateRoundRectPath(&borderPath, bounds, 4, -2);
			Utilities::CreateRoundRectPath(&secondaryBorderPath, bounds, 4, -1);
			Utilities::CreateRoundRectPath(&tertiaryBorderPath, bounds, 4);
			
			graphics.FillPath(&linearGradientBrush1, &fillPath1);
			graphics.FillPath(&linearGradientBrush2, &fillPath2);
			graphics.DrawPath(&borderPen,&borderPath);
			graphics.DrawPath(&secondaryBorderPen,&secondaryBorderPath);
			graphics.DrawPath(&tertiaryBorderPen,&tertiaryBorderPath);
		}
	}
}


void PaintedButton::Clicked(PBEVENTPROC ptr)
{
	onClickPtr = ptr;
}

void PaintedButton::MouseEnter(PBEVENTPROC ptr)
{
	onMouseEnterPtr = ptr;
}

void PaintedButton::MouseLeave(PBEVENTPROC ptr)
{
	onMouseLeavePtr = ptr;
}

void PaintedButton::RightMouseButtonUp(PBEVENTPROC ptr)
{
	onRightMouseButtonUpPtr = ptr;
}


void PaintedButton::CallPBEvent(PBEVENTPROC ptr)
{
	if (ptr)
		ptr(this, tag);
}


void PaintedButton::Hide()
{
	visible = buttonHover = false;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

void PaintedButton::Show()
{
	visible = true;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

bool PaintedButton::IsVisible()
{
	return visible;
}

HWND PaintedButton::GetParentWindow()
{
	return parentHWnd;
}

tstring PaintedButton::GetText()
{
	return text;
}

void PaintedButton::SetText(tstring text, int leftPadding, int topPadding, int rightPadding, int bottomPadding)
{
	this->text = text;

	textPadding.left = leftPadding;
	textPadding.top = topPadding;
	textPadding.right = rightPadding;
	textPadding.bottom = bottomPadding;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

COLORREF PaintedButton::GetTextColor()
{
	return textColor;
}

void PaintedButton::SetTextColor(COLORREF cr)	
{	
	textColor = cr;
}

PaintedButton::GradientMode PaintedButton::GetGradientMode()
{
	return gradientMode;
}

void PaintedButton::SetGradientMode(PaintedButton::GradientMode mode)
{
	gradientMode = mode;
}

RECT PaintedButton::GetBounds()
{
	return bounds;
}

void PaintedButton::SetBounds(RECT value)
{
	bounds = value;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

void PaintedButton::SetBounds(LONG left, LONG top, LONG right, LONG bottom)
{
	bounds.left = left;
	bounds.top = top;
	bounds.right = right;
	bounds.bottom = bottom;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

SIZE PaintedButton::GetSize()
{
	SIZE size={0};

	size.cx = RECTWIDTH(bounds);
	size.cy = RECTHEIGHT(bounds);

	return size;
}

void PaintedButton::SetSize(SIZE value)
{
	bounds.right = bounds.left + value.cx;
	bounds.bottom = bounds.top + value.cy;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

void PaintedButton::SetSize(LONG cx, LONG cy)
{
	bounds.right = bounds.left + cx;
	bounds.bottom = bounds.top + cy;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

POINT PaintedButton::GetLocation()
{
	POINT point={0};

	point.x = bounds.left;
	point.y = bounds.top;

	return point;
}

void PaintedButton::SetLocation(POINT value)
{
	bounds.right = value.x + GetSize().cx;
	bounds.bottom = value.y + GetSize().cy;
	bounds.left = value.x;
	bounds.top = value.y;
	
	InvalidateRect(parentHWnd, &bounds, TRUE);
}

void PaintedButton::SetLocation(LONG x, LONG y)
{	
	bounds.right = x + GetSize().cx;
	bounds.bottom = y + GetSize().cy;
	bounds.left = x;
	bounds.top = y;

	InvalidateRect(parentHWnd, &bounds, TRUE);
}

LPVOID PaintedButton::GetTag()
{
	return tag;
}

void PaintedButton::SetTag(LPVOID lpVoid)
{
	tag = lpVoid;
}

bool PaintedButton::GetCheckable()
{
	return checkable;
}

void PaintedButton::SetCheckable(bool value)
{
	checkable = value;

	if (!value)
	{
		buttonChecked = false;
		InvalidateRect(parentHWnd, &bounds, TRUE);
	}
}

bool PaintedButton::GetChecked()
{
	return buttonChecked;
}

void PaintedButton::SetChecked(bool value)
{
	buttonChecked = value;
	InvalidateRect(parentHWnd, &bounds, TRUE);
}

void PaintedButton::PerformClick()
{
	if (checkable)	
		buttonChecked = !buttonChecked;

	CallPBEvent(onClickPtr);

	InvalidateRect(parentHWnd, &bounds, TRUE); 
}

void PaintedButton::Refresh()
{
	InvalidateRect(parentHWnd, &bounds, TRUE); 
}

DWORD PaintedButton::GetTextFormat()
{
	return this->textFormat;
}

void PaintedButton::SetTextFormat(DWORD format)
{
	this->textFormat = format;
	InvalidateRect(parentHWnd, &bounds, TRUE);
}

int PaintedButton::GetFontSize()
{
	return this->fontSize;
}

void PaintedButton::SetFontSize(int size)
{
	this->fontSize = size;
	InvalidateRect(parentHWnd, &bounds, TRUE);
}

int PaintedButton::GetFontWeight()
{
	return this->fontWeight;
}

void PaintedButton::SetFontWeight(LONG weight)
{
	this->fontWeight = weight;
	InvalidateRect(parentHWnd, &bounds, TRUE);
}